#npm run watch laravel
Explore tagged Tumblr posts
Text
Laravel 8 Install Bootstrap Example Tutorial
In this blog, we will talk about Laravel 8 install bootstrap 4. you can see how to install bootstrap 4 in Laravel 8. In the event that you have a question about how to utilize bootstrap in Laravel 8, I will give basic model with the arrangement. You’ll learn Laravel 8 npm install bootstrap 4. You will do the accompanying things for install bootstrap for Laravel 8.Assuming you are a novice with Laravel 8, I can assist you with installing bootstrap 4 in Laravel 8. it’s an exceptionally basic approach to install utilizing Laravel ui author bundle. Laravel ui bundle add Laravel 8 help.Laravel ui gives an approach to install bootstrap, vue, and react setup. they additionally give auth framework to login and enlist. Laravel 8 furnish a simple approach to work with bootstrap, vue and react.For installation of bootstrap 4 in your Laravel 8 projects then you have to install the following Laravel ui composer package to get the command:Composer require Laravel/ui After effectively install above bundle then we are prepared to install bootstrap 4 with our application.we can install two way, one is a straightforward bootstrap 4 setup install and another is install bootstrap 4 with auth. So how about we see both way.Install Bootstrap 4php artisan ui bootstrapInstall Bootstrap 4 with authphp artisan ui bootstrap --authNext we installed bootstrap, and you can watch your resource directory js folder. You also have to install npm and run it. so let’s run both command:Install NPMnpm install Run NPMnpm run dev In this way, you can work with your bootstrap 4 apps. You can use it as given bellow:
This is example from CodeSolutionStuff.com
I hope you will like the content and it will help you to learn Laravel 8 Install Bootstrap Example Tutorial If you like this content, do share. Read the full article
#bootstrap4#howtousebootstrapinlaravel8#installbootstrap4inlaravel8#installbootstrapforlaravel8#laravel8installbootstrap4#laravel8npminstallbootstrap4#laravelui#laraveluibootstrap4#usebootstrap4inlaravel8
0 notes
Video
youtube
🎬 دوره ی آموزش طلائی فریمورک لاراول به زبان فارسی 🎬 جلسه ی : 12 🟢 موضوع این جلسه :
✔️ آموزش دانلود و نصب کردن bulma-rtl روی فریمورک لاراول و میکس کردن آن ✔️ آموزش استفاده از npm run dev و npm run production و npm run watch لاراول میکس ✔️ آموزش پروژه محور ساخت صفحه ی لاگین اینستاگرام
--- :: جزییات دوره :: ✔️ تعداد کل جلسات : 50 عدد درآینده ممکن است بیشتر شود ✔️ مدرس دوره : مهندس نیک زاد ✔️ نسخه ی لاراول : تمامی نسخه های لاراول ✔️ لینک نسخه ی اصلی دوره : https://avasam.ir/product/54 --- چرا باید فریمورک لاراول را بعنوان یک برنامه نویس وب یاد بگیریم ؟ لاراول یکی از محبوب ترین فریمورک های زبان برنامه نویسی پی اچ پی است همانطور که میدانید زبان پی اچ پی به خودی خود زبانی سریع قدرتمند و محبوب برای توسعه و ساختن انواع وب سایت ها است و هم اکنون هشتاد درصد وب سایت های دنیا با زبان پی اچ پی اجرا میگردد. لاراول به همراه صدها ابزار جدید به شما کمک میکند که توسعه و ساخت انواع وب سایت های قدرتمند را در کمترین زمان ممکن انجام دهید. لاراول بخاطر وابستگی های زیادی که دارد بواسطه ی کامپوزر نصب و اجرا میگردد و همین بسته های وابسته به هم امکانات فراوانی را به این فریمورک جمع آوری کرده است از نظر سرعت و امنیت بسیار عالی است و هم اکنون اکثر استارتاپ ها به سمت لاراول حرکت کرده اند و همچنین بازار کار بسیار عالی چه در ایران و چه در خارج از ایران دارد . آموزش فریمورک لاراول را جدی بگیرید و از این دوره ی آموزشی لاراول که توسط مهندس نیکزاد با زحمات فراوان ساخته شده است نهایت بهره را ببرید پیروز باشید . −−− * website : https://avasam.ir * tg channel : https://t.me/avasam_edu * instagram : https://instagram.com/avasam_edu * gold laravel course orginal link : https://avasam.ir/product/54 --- #laravel #laravel_tutorial #لاراول #آموزش_لاراول #آموزش_رایگان_لاراول
0 notes
Text
Laravel + Vue.js AdminPanel Generator
News / May 11, 2018
Laravel + Vue.js AdminPanel Generator
Laravel and Vue.js are often used together. With more tools on these technologies are released, here’s one of them – presenting to you Vue+Laravel Admin Panel Generator.
Disclaimer: I’m the founder and one of the developers of this tool, and also Laravel-only generator QuickAdminPanel, but the goal in this article is not only to present you the product, but explain what it generates, and how Vue + Laravel work together. Also, you will find an example project with source available on Github.
How does the generator work?
For those who prefer video, here’s a quick demo:
youtube
Now, let’s look at it with more details.
Step 1. You create your panel without coding, just adding menu items and fields.
Step 2. At any point, you can view the generated code, file by file.
Step 3. Then you download the code and install it – locally or on your remote server, with these commands:
composer install php artisan key:generate php artisan migrate --seed php artisan passport:install
Of course, your .env file should be configured at that point.
And then, on the front-end:
npm install npm run dev
Step 4. That’s it; you have your panel.
Step 5. The most important thing: you can change the code however you want, it’s pure Laravel+Vue, without our generator’s package as a dependency. That’s the main difference from packages like Voyager or Laravel Backpack (which are both excellent, by the way!).
What are we generating – structure of the project
After you download the project, you see something like this:
Generated Code: Back-end Laravel
Let’s first analyze the back-end Laravel part, which serves as API:
Here’s routes/api.php file:
Route::group(['prefix' => '/v1', 'middleware' => ['auth:api'], 'namespace' => 'Api\V1', 'as' => 'api.'], function () { Route::post('change-password', 'ChangePasswordController@changePassword')->name('auth.change_password'); Route::apiResource('roles', 'RolesController'); Route::apiResource('users', 'UsersController'); Route::apiResource('companies', 'CompaniesController'); Route::apiResource('employees', 'EmployeesController'); });
You can see apiResource for every CRUD, and also one separate POST for changing the password.
Controllers are namespaces under Api/V1, so here’s our app/Http/Controllers/Api/V1/CompaniesController.php:
namespace App\Http\Controllers\Api\V1; use App\Company; use App\Http\Controllers\Controller; use App\Http\Resources\Company as CompanyResource; use App\Http\Requests\Admin\StoreCompaniesRequest; use App\Http\Requests\Admin\UpdateCompaniesRequest; use Illuminate\Http\Request; class CompaniesController extends Controller { public function index() { return new CompanyResource(Company::with([])->get()); } public function show($id) { $company = Company::with([])->findOrFail($id); return new CompanyResource($company); } public function store(StoreCompaniesRequest $request) { $company = Company::create($request->all()); return (new CompanyResource($company)) ->response() ->setStatusCode(201); } public function update(UpdateCompaniesRequest $request, $id) { $company = Company::findOrFail($id); $company->update($request->all()); return (new CompanyResource($company)) ->response() ->setStatusCode(202); } public function destroy($id) { $company = Company::findOrFail($id); $company->delete(); return response(null, 204); } }
We have a typical resourceful Controller, with one exception – Resources classes, which have been available since Laravel 5.5.
In our case, every resource is a simple conversion to an array, here’s a file app/Http/Resources/Company.php
namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class Company extends JsonResource { /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return parent::toArray($request); } }
But you can extend it, adding your logic on top – see more examples here and here.
Finally, Laravel Passport protects all the routes – when installing the project, you need to run this:
php artisan passport:install
As an overall back-end result, every Controller is responsible for that specific CRUD operations called to the API, from Vue.js front-end.
Generated Code: Front-end Vue.js
Now, let’s take a look at front-end part. The main file for this is resources/client/assets/js/app.js, where we initiate the Vue and some libraries:
// ... window.Vue = require('vue') Vue.prototype.$eventHub = new Vue() import router from './routes' import store from './store' import Datatable from 'vue2-datatable-component' import VueAWN from 'vue-awesome-notifications' import vSelect from 'vue-select' import datePicker from 'vue-bootstrap-datetimepicker' import VueSweetalert2 from 'vue-sweetalert2' import 'eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.css' Vue.use(Datatable) Vue.use(VueAWN, { position: 'top-right' }) Vue.use(datePicker) Vue.use(VueSweetalert2) Vue.component('back-buttton', require('./components/BackButton.vue')) Vue.component('bootstrap-alert', require('./components/Alert.vue')) Vue.component('event-hub', require('./components/EventHub.vue')) Vue.component('vue-button-spinner', require('./components/VueButtonSpinner.vue')) Vue.component('v-select', vSelect) moment.updateLocale(window.app_locale, { week: { dow: 1 } }) const app = new Vue({ data: { relationships: {}, dpconfigDate: { format: window.date_format_moment }, dpconfigTime: { format: window.time_format_moment }, dpconfigDatetime: { format: window.datetime_format_moment, sideBySide: true } }, router, store }).$mount('#app')
Next, every CRUD has its own set of components:
For showing the data table, we’re using vue2-datatable-component – here’s full code of resources/clients/assets/components/cruds/Companies/Index.vue:
<template> <section class="content-wrapper" style="min-height: 960px;"> <section class="content-header"> <h1>Companies</h1> </section> <section class="content"> <div class="row"> <div class="col-xs-12"> <div class="box"> <div class="box-header with-border"> <h3 class="box-title">List</h3> </div> <div class="box-body"> <div class="btn-group"> <router-link :to="{ name: xprops.route + '.create' }" class="btn btn-success btn-sm"> <i class="fa fa-plus"></i> Add new </router-link> <button type="button" class="btn btn-default btn-sm" @click="fetchData"> <i class="fa fa-refresh" :class="{'fa-spin': loading}"></i> Refresh </button> </div> </div> <div class="box-body"> <div class="row" v-if="loading"> <div class="col-xs-4 col-xs-offset-4"> <div class="alert text-center"> <i class="fa fa-spin fa-refresh"></i> Loading </div> </div> </div> <datatable v-if="!loading" :columns="columns" :data="data" :total="total" :query="query" :xprops="xprops" /> </div> </div> </div> </div> </section> </section> </template> <script> import { mapGetters, mapActions } from 'vuex' import DatatableActions from '../../dtmodules/DatatableActions' import DatatableSingle from '../../dtmodules/DatatableSingle' import DatatableList from '../../dtmodules/DatatableList' import DatatableCheckbox from '../../dtmodules/DatatableCheckbox' export default { data() { return { columns: [ { title: '#', field: 'id', sortable: true, colStyle: 'width: 50px;' }, { title: 'Name', field: 'name', sortable: true }, { title: 'Description', field: 'description', sortable: true }, { title: 'Actions', tdComp: DatatableActions, visible: true, thClass: 'text-right', tdClass: 'text-right', colStyle: 'width: 130px;' } ], query: { sort: 'id', order: 'desc' }, xprops: { module: 'CompaniesIndex', route: 'companies' } } }, created() { this.$root.relationships = this.relationships this.fetchData() }, destroyed() { this.resetState() }, computed: { ...mapGetters('CompaniesIndex', ['data', 'total', 'loading', 'relationships']), }, watch: { query: { handler(query) { this.setQuery(query) }, deep: true } }, methods: { ...mapActions('CompaniesIndex', ['fetchData', 'setQuery', 'resetState']), } } </script> <style scoped> </style>
Quite a lot of code, isn’t it? Of course, it could be more straightforward, but we tried to follow the official documentation and best practices, generating code for the cases that could be extended for bigger projects.
Next, we can take a look at Create.vue:
<template> <section class="content-wrapper" style="min-height: 960px;"> <section class="content-header"> <h1>Companies</h1> </section> <section class="content"> <div class="row"> <div class="col-xs-12"> <form @submit.prevent="submitForm"> <div class="box"> <div class="box-header with-border"> <h3 class="box-title">Create</h3> </div> <div class="box-body"> <back-buttton></back-buttton> </div> <bootstrap-alert /> <div class="box-body"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" name="name" placeholder="Enter Name" :value="item.name" @input="updateName" > </div> <div class="form-group"> <label for="description">Description</label> <textarea rows="3" class="form-control" name="description" placeholder="Enter Description" :value="item.description" @input="updateDescription" > </textarea> </div> </div> <div class="box-footer"> <vue-button-spinner class="btn btn-primary btn-sm" :isLoading="loading" :disabled="loading" > Save </vue-button-spinner> </div> </div> </form> </div> </div> </section> </section> </template> <script> import { mapGetters, mapActions } from 'vuex' export default { data() { return { // Code... } }, computed: { ...mapGetters('CompaniesSingle', ['item', 'loading']) }, created() { // Code ... }, destroyed() { this.resetState() }, methods: { ...mapActions('CompaniesSingle', ['storeData', 'resetState', 'setName', 'setDescription']), updateName(e) { this.setName(e.target.value) }, updateDescription(e) { this.setDescription(e.target.value) }, submitForm() { this.storeData() .then(() => { this.$router.push({ name: 'companies.index' }) this.$eventHub.$emit('create-success') }) .catch((error) => { console.error(error) }) } } } </script> <style scoped> </style>
Edit and Show components for the CRUD are pretty similar, so won’t discuss them here.
In addition to that Vue code, there are many small details and helpers like Sweet Alert, Notifications, Datepickers, and setting/getting relationships data for the forms. I guess I will leave it for you to analyze.
Notice: The choice of Vue.js libraries is pretty subjective, and it was the most challenging part of the project – to choose the Vue libraries to trust. Ecosystem still lacks standards, or 100% trusted open-source – a lot of movement in the market, some libraries are better supported than others. So it’s always hard to guess, and the best libraries will probably change with time, or new ones will appear.
That’s the end of a quick overview of Vue+Laravel QuickAdminPanel, try it out here: https://vue.quickadminpanel.com
Finally, here’s the source of a demo-project with two CRUDs: Companies and Customers.
I hope our generator will not only save you time on writing code but also show you how Vue can work with Laravel. Our way of structuring this code is not the only way, and you can structure your code differently, but we tried our best to stick to standards.
via Laravel News https://ift.tt/2wzPFV6
0 notes
Text
Laravel - Create Blog and Admin Panel | How to use Vuejs with Laravel (like system #1) #33
Laravel – Create Blog and Admin Panel | How to use Vuejs with Laravel (like system #1) #33
[ad_1]
Create Best Blog with Admin panel on Laravel, How to use Vuejs with laravel and webpack, npm run watch
Source code https://goo.gl/2CMwup
Become My Patron here https://goo.gl/NcvDQh
You can donate any amount via Paypal follow this link https://goo.gl/JhWsKC
Join Our Slack Community – https://goo.gl/pqCjZH
You May Also Like
Blog with Admin panel Series –
View On WordPress
0 notes
Text
Creación de una web app con Laravel 5.3 [Configuración del proyect] (3)
En el capitulo anterior vimos como crear un proyecto con la linea de comando de “laravel”. Ahora nos dispondremos a configurarlo, como mencione anteriormente no nos meteremos en detalle sobre la estructura de archivos y directorios de Laravel, pero lo pueden revisar en este link: https://laravel.com/docs/5.3/structure.
Antes de iniciar con la configuracion tendremos que instalar las dependencias Node de nuestro proyecto el cual configuraremos dos archivos que se encuentran en / de nuestro proyecto: package.json y gulpfile.js
Archivo package.json
Este archivo ya viene cuando se crea el proyecto y en el se encuentra la configuracion para instalar las dependencias de Node. Si no se encuentra simplemente creen el archivo en la raiz del proyecto como “package.json” y dentro le ponen lo siguiente:
{ "private": true, "scripts": { "prod": "gulp --production", "dev": "gulp watch" }, "devDependencies": { "bootstrap-sass": "^3.3.7", "gulp": "^3.9.1", "jquery": "^3.1.0", "laravel-elixir": "^6.0.0-9", "laravel-elixir-vue-2": "^0.2.0", "laravel-elixir-webpack-official": "^1.0.2", "lodash": "^4.16.2", "vue": "^2.0.1", "vue-resource": "^1.0.3" }, "dependencies": { "vue-materials": "^1.0.7-rc.6", "vue-typeahead": "^2.3.0" } }
Una vez hecho esto ejecutamos el comando para instalar las dependencias Node:
npm install
Una vez ejecutado este comando nos creara las dependecias Node en el directorio “/node_modules” donde se podran usar las librerias antes mencioandas en el archivo y necesarias para el proyecto.
Recordemos que para hacer esto tenemos que estar en la carpeta de nuestros proyecto en la consola o terminal. Por lo general en esta ruta: “/MAMP/htdocs/blog”
Archivo gulpfile.js
Este archivo es necesario para ejecutar tareas para compilacion de Javascript y archivos Sass; necesitaremos que este creado este archivo en raiz, si no lo crearemos como “gulpfile.js”, y le pondremos lo siguiente:
const elixir = require('laravel-elixir'); require('laravel-elixir-vue-2'); /* |-------------------------------------------------------------------------- | Elixir Asset Management |-------------------------------------------------------------------------- | | Elixir provides a clean, fluent API for defining some basic Gulp tasks | for your Laravel application. By default, we are compiling the Sass | file for our application, as well as publishing vendor resources. | */ elixir(mix => { mix.sass('app.scss') .webpack('app.js'); });
En general este archivo ejecuta las tareas de compilación de los estilos Sass y el webpack de javascript “app.js” que lo utilizaremos mas adelante cuando usemos Vue JS. Para la compilacion de estos archivos se encuentran en la carpeta “resources/assets/js” y “resources/assets/sass”. Aquí es donde vamos a programar estos archivos y Gulp se va encargar de la compilación automática, cuando se compilan los guarda en “public/css” y “public/js”.
Mas adelante veremos como ejecutar el comando “gulp” cuando usemos javascript, sass y vue js en la vista.
Archivo .env
Este archivo es donde reside la configuracion o parametros de configuracion de Laravel. Aqui se podra configurar los datos de la base de datos y credenciales del servidor de correo principalmente, tiene mas opciones de parametros de configuracion, por el momento usaremos los de la base de datos. Practicamente asi se debe de ver nuestro archivo .env:
APP_ENV=local APP_KEY=base64:PQW8Ry4mz0X+VkqqGJz9azNmND+8VSX0LYD5vlgLSjY= APP_DEBUG=true APP_LOG_LEVEL=debug APP_URL=http://localhost DB_CONNECTION=mysql #Nombre de nuestra conexion DB_HOST=127.0.0.1 #IP o DNS de nuestro servidor de base de datos DB_PORT=3306 #El puerto del servidor DB_DATABASE=blog #Nombre de la base de datos DB_USERNAME=root #Usuario de la base de datos DB_PASSWORD= #Passwor de la base de datos BROADCAST_DRIVER=log CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_DRIVER=smtp MAIL_HOST=mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null
Como podrán ver para configurar la base de datos viene con el prefijo “DB_” en donde pondremos toda la información relacionada a nuestra base de datos, esta información puede variar dependiendo de su configuración de MySQL.
Archivo /config/database.php
Después de configurar el archivo “.env” debemos configurar este archivo ya que aqui es donde le decimos que conexión de base de datos debemos usar. La flexibilidad de Laravel hace que podamos usar diferentes manejadores de base de datos(MySQL, Oracle, PosgreSQL, etc ...) y diferentes base de datos en nuestro proyecto. La estructura de este archivo debe quedar como sigue:
<?php return [ /* |-------------------------------------------------------------------------- | PDO Fetch Style |-------------------------------------------------------------------------- | | By default, database results will be returned as instances of the PHP | stdClass object; however, you may desire to retrieve records in an | array format for simplicity. Here you can tweak the fetch style. | */ 'fetch' => PDO::FETCH_OBJ, /* |-------------------------------------------------------------------------- | Default Database Connection Name |-------------------------------------------------------------------------- | | Here you may specify which of the database connections below you wish | to use as your default connection for all database work. Of course | you may use many connections at once using the Database library. | */ 'default' => env('DB_CONNECTION', 'mysql'), /* |-------------------------------------------------------------------------- | Database Connections |-------------------------------------------------------------------------- | | Here are each of the database connections setup for your application. | Of course, examples of configuring each database platform that is | supported by Laravel is shown below to make development simple. | | | All database work in Laravel is done through the PHP PDO facilities | so make sure you have the driver for your particular database of | choice installed on your machine before you begin development. | */ 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', ], 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ], 'pgsql' => [ 'driver' => 'pgsql', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '5432'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', 'schema' => 'public', 'sslmode' => 'prefer', ], ], /* |-------------------------------------------------------------------------- | Migration Repository Table |-------------------------------------------------------------------------- | | This table keeps track of all the migrations that have already run for | your application. Using this information, we can determine which of | the migrations on disk haven't actually been run in the database. | */ 'migrations' => 'migrations', /* |-------------------------------------------------------------------------- | Redis Databases |-------------------------------------------------------------------------- | | Redis is an open source, fast, and advanced key-value store that also | provides a richer set of commands than a typical key-value systems | such as APC or Memcached. Laravel makes it easy to dig right in. | */ 'redis' => [ 'cluster' => false, 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], ], ];
Si observamos bien toda la información se obtiene del archivo “.env” por medio de la funcion “env()”. La conexión por default se define con el apartado “'default' => env('DB_CONNECTION', 'mysql'),”, en donde se le pasa como valor el nombre de la conexion definida en el archivo “.env”. En general es un array asociativo de PHP que se usa como configuración para Laravel.
El array “connections” se puede configurar en los modelos para poder usar ese tipo de manejador de base de datos y su base de datos, aqui es donde viene la flexibilidad de Laravel; por el momento solo usaremos el Driver de MySQL.
Archivo config/app.php
Este archivo se configura las opciones generales de nuestra aplicación como por ejemplo: paquetes de Laravel, librerías, métodos de encriptación, idiomas, usos horarios etc ..
Aqui nada mas modificaremos nuestro timezone que viene en el apartado del array “'timezone' => 'UTC',”, este lo modificaremos a nuestro gusto dependiendo de que zona horaria manejaremos. La estructura del archivo es la siguiente:
<?php return [ /* |-------------------------------------------------------------------------- | Application Name |-------------------------------------------------------------------------- | | This value is the name of your application. This value is used when the | framework needs to place the application's name in a notification or | any other location as required by the application or its packages. */ 'name' => 'Laravel', /* |-------------------------------------------------------------------------- | Application Environment |-------------------------------------------------------------------------- | | This value determines the "environment" your application is currently | running in. This may determine how you prefer to configure various | services your application utilizes. Set this in your ".env" file. | */ 'env' => env('APP_ENV', 'production'), /* |-------------------------------------------------------------------------- | Application Debug Mode |-------------------------------------------------------------------------- | | When your application is in debug mode, detailed error messages with | stack traces will be shown on every error that occurs within your | application. If disabled, a simple generic error page is shown. | */ 'debug' => env('APP_DEBUG', false), /* |-------------------------------------------------------------------------- | Application URL |-------------------------------------------------------------------------- | | This URL is used by the console to properly generate URLs when using | the Artisan command line tool. You should set this to the root of | your application so that it is used when running Artisan tasks. | */ 'url' => env('APP_URL', 'http://localhost'), /* |-------------------------------------------------------------------------- | Application Timezone |-------------------------------------------------------------------------- | | Here you may specify the default timezone for your application, which | will be used by the PHP date and date-time functions. We have gone | ahead and set this to a sensible default for you out of the box. | */ 'timezone' => 'UTC', /* |-------------------------------------------------------------------------- | Application Locale Configuration |-------------------------------------------------------------------------- | | The application locale determines the default locale that will be used | by the translation service provider. You are free to set this value | to any of the locales which will be supported by the application. | */ 'locale' => 'en', /* |-------------------------------------------------------------------------- | Application Fallback Locale |-------------------------------------------------------------------------- | | The fallback locale determines the locale to use when the current one | is not available. You may change the value to correspond to any of | the language folders that are provided through your application. | */ 'fallback_locale' => 'en', /* |-------------------------------------------------------------------------- | Encryption Key |-------------------------------------------------------------------------- | | This key is used by the Illuminate encrypter service and should be set | to a random, 32 character string, otherwise these encrypted strings | will not be safe. Please do this before deploying an application! | */ 'key' => env('APP_KEY'), 'cipher' => 'AES-256-CBC', /* |-------------------------------------------------------------------------- | Logging Configuration |-------------------------------------------------------------------------- | | Here you may configure the log settings for your application. Out of | the box, Laravel uses the Monolog PHP logging library. This gives | you a variety of powerful log handlers / formatters to utilize. | | Available Settings: "single", "daily", "syslog", "errorlog" | */ 'log' => env('APP_LOG', 'single'), 'log_level' => env('APP_LOG_LEVEL', 'debug'), /* |-------------------------------------------------------------------------- | Autoloaded Service Providers |-------------------------------------------------------------------------- | | The service providers listed here will be automatically loaded on the | request to your application. Feel free to add your own services to | this array to grant expanded functionality to your applications. | */ 'providers' => [ /* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Cookie\CookieServiceProvider::class, Illuminate\Database\DatabaseServiceProvider::class, Illuminate\Encryption\EncryptionServiceProvider::class, Illuminate\Filesystem\FilesystemServiceProvider::class, Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, Illuminate\Notifications\NotificationServiceProvider::class, Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, /* * Package Service Providers... */ // /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, /** * Laravel Scout Providers */ Laravel\Scout\ScoutServiceProvider::class, TeamTNT\Scout\TNTSearchScoutServiceProvider::class, ], /* |-------------------------------------------------------------------------- | Class Aliases |-------------------------------------------------------------------------- | | This array of class aliases will be registered when this application | is started. However, feel free to register as many as you wish as | the aliases are "lazy" loaded so they don't hinder performance. | */ 'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, ], ];
Creación de la base de datos
Para crear nuestra base de datos abriremos la herramienta “phpMyAdmin” que viene en cualquier stack de XAMP y que por lo general tiene esta url “localhost/phpMyAdmin”(esto ya depende de como se configuro el ambiente de desarrollo).
Una vez abierto el phpMyAdmin nos dirigimos al menú de la parte superior y en la seccion Base de Datos o Databases damos click.
En donde dice Crear Base de Datos ponemos nuestro nombre de la base de datos en este caso “blog”, cotejamiento “utf8_general_ci”, le damos click en el botón “Crear” o “Create”.
Y con eso tenemos ya lista nuestra base de datos en nuestro servidor de desarrollo. En el siguiente capitulo veremos como hacer migraciones, factories y modelos que son componentes de Laravel para la capa de datos.
0 notes
Text
Build a React App With a Laravel Back End: Part 2, React
What You'll Be Creating
This is the second and final part of the series on building a React application with a Laravel back end. In the first part of the series, we created a RESTful API using Laravel for a basic product-listing application. In this tutorial, we will be developing the front end using React.
We will also consider all the available options to bridge the gap between Laravel and React. You don't need to have followed part one of the series to understand this tutorial. If you're here to see how React and Laravel fare together, you can, in fact, avoid the first part. You should head over to GitHub, clone the repo, and take the quick recap down below to get started.
A Quick Recap
In the previous tutorial, we developed a Laravel application that responds to API calls. We created routes, a controller, and a model for the simple product listing application. Since it was the controller's job to return a response to the HTTP requests, the view section was entirely skipped.
Then we discussed techniques for exception handling and validation using Laravel. By the end of the tutorial, we had a Laravel back-end API. We can now use this API to build applications for both the web and a wide range of mobile devices.
In this tutorial, we will be shifting our focus towards the front end. The first half of the tutorial is about setting up React in a Laravel environment. I will also introduce you to Laravel Mix (supported by Laravel 5.4 and later), which is an API for compiling assets. In the second half of the tutorial, we will start building a React application from scratch.
Setting Up React in Laravel
Laravel Mix was introduced in Laravel 5.4, and it is currently the ideal way to hook up React and Laravel. With Laravel 5.5, the whole process was made much easier. I've described both methods below.
Using the React Preset Command (Laravel 5.5)
Laravel 5.5 has a brand new feature that lets you scaffold the code for React components using artisan's preset react command. In previous versions of Laravel, setting up React inside Laravel wasn't this easy. If you're running the latest version of Laravel, then run the below command to add a React preset to your project.
php artisan preset react
Laravel by default gets shipped with the Vue preset, and the above command replaces all instances of Vue with React. Interestingly, if you don't need a preset, you can remove them altogether using the php artisan preset none command.
If everything goes well, this should show up in your terminal.
React scaffolding installed successfully. Please run "npm install && npm run dev" to compile your fresh scaffolding.
In the background, Laravel uses Laravel Mix, which is a smooth wrapper for webpack. Webpack, as you might already know, is a module bundler. It resolves all the module dependencies and generates the necessary static assets for JavaScript and CSS. React requires a module bundler to work, and webpack perfectly fits into that role. So Laravel Mix is the layer that sits on top of webpack and makes it easier to use webpack in Laravel.
A better understanding of how Laravel Mix works is important if you need to customize the webpack configuration at a later time. The React preset command gives us no information about how things work in the background. So let's remove the React preset and retrace the steps manually instead.
Manual Method (Laravel 5.4)
If you're running Laravel 5.4, or if you are just curious to see how Laravel Mix is configured, here are the steps that you need to follow:
Install react, react-dom and babel-preset-react using npm. It might be a good idea to have yarn installed too. It's no secret that Laravel and React prefer yarn over npm.
Head over to webpack.mix.js, located inside the root directory of your Laravel project. This is the configuration file where you declare how your assets should be compiled. Replace the line mix.js('resources/assets/js/app.js', 'public/js'); with mix.react('resources/assets/js/app.js', 'public/js');. app.js is the entry point for our JavaScript files, and the compiled files will be located inside public/js. Run npm install in the terminal to install all the dependencies.
Next, go to resources/assets/js. There's already a components folder and a couple of other JavaScript files. React components will go into the components directory. Remove the existing Example.vue file and create a new file for a sample React component.
resources/assets/js/component/Main.js
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; /* An example React component */ class Main extends Component { render() { return ( <div> <h3>All Products</h3> </div> ); } } export default Main; /* The if statement is required so as to Render the component on pages that have a div with an ID of "root"; */ if (document.getElementById('root')) { ReactDOM.render(<Main />, document.getElementById('root')); }
Update app.js to remove all the Vue-related code and import the React component instead.
resources/assets/js/app.js
require('./bootstrap'); /* Import the Main component */ import Main from './components/Main';
Now, we just need to make the assets accessible to the View. The view files are located inside the resources/views directory. Let's add a <script> tag to welcome.blade.php, which is the default page rendered when you navigate to localhost:8000/. Remove the contents of the view file and replace it with the code below:
resources/views/welcome.blade.php
<!doctype html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel React application</title> <link href="" rel="stylesheet" type="text/css"> </head> <body> <h2 style="text-align: center"> Laravel and React application </h2> <div id="root"></div> <script src="" ></script> </body> </html>
Finally, execute npm run dev or yarn run dev to compile the assets. If you visit localhost:8000, you should see:
React embedded inside Laravel's view.
The package.json has a watch script that auto-compiles the assets when any changes are detected. To enable this mode, run npm run watch.
Congrats, you've successfully configured React to work with Laravel. Now, let's create some React components for the front end.
Developing the React Application
If you're new to React, you will find the rest of the tutorial somewhat challenging. I recommend taking the React Crash Course for Beginners series to get acquainted with the React concepts better. Let's get started!
A React application is built around components. Components are the most important structure in React, and we have a directory dedicated for components.
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen. — Official React Docs
For the application that we are building, we will start with a basic component that displays all the products returned by the server. Let's name it the Main component. The component should take care of the following things initially:
Fetch all the products from the API (GET /api/products).
Store the product data in its state.
Display the product data.
React isn't a full-fledged framework, and hence the library doesn't have any AJAX features on its own. I will be using fetch(), which is a standard JavaScript API for fetching the data from the server. But there are tons of alternatives to make AJAX calls to the server.
resources/assets/js/component/Main.js
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; /* Main Component */ class Main extends Component { constructor() { super(); //Initialize the state in the constructor this.state = { products: [], } } /*componentDidMount() is a lifecycle method * that gets called after the component is rendered */ componentDidMount() { /* fetch API in action */ fetch('/api/products') .then(response => { return response.json(); }) .then(products => { //Fetched product is stored in the state this.setState({ products }); }); } renderProducts() { return this.state.products.map(product => { return ( /* When using list you need to specify a key * attribute that is unique for each list item */ <li key={product.id} > { product.title } </li> ); }) } render() { /* Some css code has been removed for brevity */ return ( <div> <ul> { this.renderProducts() } </ul> </div> ); } }
Here we're initializing the state of products to an empty array in the constructor. Once the component mounts, we use fetch() to retrieve the products from /api/products and store it in the state. The render method is used to describe the UI of the component. All the products get rendered as a list there.
The page just lists the product titles, which is boring. Moreover, we don't have any interactive elements in there yet. Let's make the product title clickable, and on click, more details about the product will get rendered.
Displaying Product Data
Here's the list of things that we need to cover:
A state to track the product that was clicked. Let's call it currentProduct with an initial null value.
When a product title is clicked, this.state.currentProduct is updated.
The product details of the concerned product are displayed on the right. Until a product is selected, it displays the "No product selected" message.
resources/assets/js/component/Main.js
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; /* Main Component */ class Main extends Component { constructor() { super(); /* currentProduct keeps track of the product currently * displayed */ this.state = { products: [], currentProduct: null } } componentDidMount() { //code omitted for brevity } renderProducts() { return this.state.products.map(product => { return ( //this.handleClick() method is invoked onClick. <li onClick={ () =>this.handleClick(product)} key={product.id} > { product.title } </li> ); }) } handleClick(product) { //handleClick is used to set the state this.setState({currentProduct:product}); } render() { /* Some css code has been removed for brevity */ return ( <div> <ul> { this.renderProducts() } </ul> </div> ); } }
Here we've added createProduct into the state and initialized it with the value null. The line onClick={ () =>this.handleClick(product) } invokes the handleClick() method when the list item is clicked. The handleClick() method updates the state of currentProduct.
Now to display the product data, we can either render it inside the Main component or create a new component. As previously mentioned, splitting the UI into smaller components is the React way of doing things. So we will create a new component and name it Product.
The Product component is nested inside the Main component. The Main component passes its state as props. The Product component accepts this props as input and renders the relevant information.
resources/assets/js/component/Main.js
render() { return ( /* The extra divs are for the css styles */ <div> <div> <h3> All products </h3> <ul> { this.renderProducts() } </ul> </div> <Product product={this.state.currentProduct} /> </div> ); } }
resources/assets/js/component/Product.js
import React, { Component } from 'react'; /* Stateless component or pure component * { product } syntax is the object destructing */ const Product = ({product}) => { const divStyle = { /*code omitted for brevity */ } //if the props product is null, return Product doesn't exist if(!product) { return(<div style={divStyle}> Product Doesnt exist </div>); } //Else, display the product data return( <div style={divStyle}> <h2> {product.title} </h2> <p> {product.description} </p> <h3> Status {product.availability ? 'Available' : 'Out of stock'} </h3> <h3> Price : {product.price} </h3> </div> ) } export default Product ;
The application should look something like this now:
Adding a New Product
We've successfully implemented the front end corresponding to retrieving all the products and displaying them. Next, we need a form to add a new product to the product list. The process for adding a product might feel a bit more complex than just fetching the data from an API.
Here's what I think is required to develop this feature:
A new stateful component that renders the UI for an input form. The component's state holds the form data.
On submit, the child component passes the state to the Main component using a callback.
The Main component has a method, say handleNewProduct(), that handles the logic for starting a POST request. Upon receiving the response, the Main component updates its state (both this.state.products and this.state.currentProduct)
That doesn't sound very complex, does it? Let's do it step by step. First, create a new component. I am going to call it AddProduct.
resources/assets/js/component/AddProduct.js
class AddProduct extends Component { constructor(props) { super(props); /* Initialize the state. */ this.state = { newProduct: { title: '', description: '', price: 0, availability: 0 } } //Boilerplate code for binding methods with `this` this.handleSubmit = this.handleSubmit.bind(this); this.handleInput = this.handleInput.bind(this); } /* This method dynamically accepts inputs and stores it in the state */ handleInput(key, e) { /*Duplicating and updating the state */ var state = Object.assign({}, this.state.newProduct); state[key] = e.target.value; this.setState({newProduct: state }); } /* This method is invoked when submit button is pressed */ handleSubmit(e) { //preventDefault prevents page reload e.preventDefault(); /*A call back to the onAdd props. The current *state is passed as a param */ this.props.onAdd(this.state.newProduct); } render() { const divStyle = { /*Code omitted for brevity */ } return( <div> <h2> Add new product </h2> <div style={divStyle}> /*when Submit button is pressed, the control is passed to *handleSubmit method */ <form onSubmit={this.handleSubmit}> <label> Title: { /*On every keystroke, the handeInput method is invoked */ } <input type="text" onChange={(e)=>this.handleInput('title',e)} /> </label> <label> Description: <input type="text" onChange={(e)=>this.handleInput('description',e)} /> </label> { /* Input fields for Price and availability omitted for brevity */} <input type="submit" value="Submit" /> </form> </div> </div>) } } export default AddProduct;
The component basically renders an input form, and all the input values are stored in the state (this.state.newProduct). Then, on form submission, handleSubmit() method gets invoked. But AddProduct needs to communicate the information back to the parent, and we do this using a callback.
The Main component, which is the parent, passes a function reference as props. The child component, AddProduct in our case, invokes this props to notify the parent of the state change. So the line this.props.onAdd(this.state.newProduct); is an example of a callback that notifies the parent component of the new product.
Now, inside the Main component, we shall declare <AddProduct /> as follows:
<AddProduct onAdd={this.handleAddProduct} />
The onAdd event handler is chained to the component's handleAddProduct() method. This method hosts the code for making a POST request to the server. If the response indicates that the product has been successfully created, the state of products and currentProducts is updated.
handleAddProduct(product) { product.price = Number(product.price); /*Fetch API for post request */ fetch( 'api/products/', { method:'post', /* headers are important*/ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(product) }) .then(response => { return response.json(); }) .then( data => { //update the state of products and currentProduct this.setState((prevState)=> ({ products: prevState.products.concat(data), currentProduct : data })) }) }
Don't forget to bind the handleProduct method to the class using this.handleAddProduct = this.handleAddProduct.bind(this); in the constructor. And here's the final version of the application:
What Next?
The application is incomplete without the delete and update features. But if you've been following the tutorial closely until now, you should be able to fill in the void without much trouble. To get you started, I've provided you the event handler logic for both the delete and update scenario.
Logic for Deleting a Product
handleDelete() { const currentProduct = this.state.currentProduct; fetch( 'api/products/' + this.state.currentProduct.id, { method: 'delete' }) .then(response => { /* Duplicate the array and filter out the item to be deleted */ var array = this.state.products.filter(function(item) { return item !== currentProduct }); this.setState({ products: array, currentProduct: null}); }); }
Logic for Updating an Existing Product
handleUpdate(product) { const currentProduct = this.state.currentProduct; fetch( 'api/products/' + currentProduct.id, { method:'put', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(product) }) .then(response => { return response.json(); }) .then( data => { /* Updating the state */ var array = this.state.products.filter(function(item) { return item !== currentProduct }) this.setState((prevState)=> ({ products: array.concat(product), currentProduct : product })) }) }
What you need to do is dive in, get your hands dirty, and finish the application using the above logic. I will drop you a hint: The delete button should ideally go inside the Product component, whereas the update feature should have a component of its own. I encourage you to take up this challenge and finish the missing components.
Summary
We've come a long way from where we started. First, we created a REST API using the Laravel framework. Then, we discussed our options for mixing Laravel and React. Finally, we built a front end to the API using React.
Although we primarily focused on creating a single-page application using React, you can create widgets or components that are mounted to specific elements in your views. React is very flexible because it's a library, and a good one.
Over the last couple of year, React has grown in popularity. In fact, we’ve a number of items in the marketplace that are available for purchase, review, implementation, and so on. If you’re looking for additional resources around React, don’t hesitate to check them out.
Have you tried experimenting with Laravel and React before? What are your thoughts? Share them with us in the comments.
via Envato Tuts+ Code http://ift.tt/2xyH9kp
0 notes
Text
Build a Serverless MERN Story App With Webtask.io — Zero to Deploy: 1
Being a fullstack developer is fun to me and a lot of us enjoy the role because it's more challenging. We have the opportunity as fullstack developers to play with every possible tool on the web and make something reasonable out of it.
Unfortunately some engineers are not fortunate enough to be in an environment that allow them showcase their fullstack powers. Either they are spitting Laravel blade template and rolling out APIs as backend developers or struggling with CSS Flexbox and React as frontend developers.
The pressure is more on frontend engineers because backend engineers can afford to have a good UI without being frontend masters. Frontend engineers just need to know a lot about their server language and even the server configuration to survive.
Serverless technology is starting the put back smiles on our faces as frontend engineers. Now we can focus on the browser and rollout servers within 3 minutes.
Our Task
The image above shows what we intend to build. It's a full functional app written in React and backed by Node, Express and Mongo DB. The backend is "Serverless" with Webtask and composed of just functions and simple Express routes.
Serverless Concept
"Server-less" is a coined term that refers to building web apps without bothering about how the server is set up. The term causes confusion to developers that are new to the concept. It doesn't mean that your app won't live on a server, rather it means that the sever setup and management is left out to be managed by the provisioning platform.
One other thing you might hear when "server-less" is discussed is Function as a Service (FaaS). Serverless technique is simplified by functions. As a developer, you end up writing and deploying compassable functions. This concept will become clearer when we start getting our hands dirty.
Webtask
Google Cloud Functions, stdlib, Azure Cloud Functions, AWS Lambda, etc are all serverless platforms you can lay your hands. The smart guys at Auth0 introduced Webtask which is yet another serverless platform which is seamlessly easy to get started with.
Webtask is used internal by the Auth0 team to manage and run their platform user custom codes. They were generous enough to make this available to the public so we can go ahead and build apps with it. My choice for Webtask is greatly influenced my how easy it is to get started with less overwhelming docs.
Setting Up Project
Our project is split into two -- the webtask backend API and a React driven frontend. Let's take care of Webtast setup first, then setup the frontend when it's time to build that.
Webtask just as you might have guessed, provides a CLI tool to make deploying you functions easy. First thing to do is install this CLI tool:
npm install -g wt-cli
To deploy functions, Webtask needs a way to identify you and your functions. Therefore, an account is needed. Head straight to the Webtask website and login. You will use your email to login to the CLI.
Run the following command to login via your CLI:
wt init <YOUR-EMAIL>
Create your project directory anywhere on your machine, add an index.jsin the directory with the following content:
module.exports = function (cb) { cb(null, 'Hello World'); }
Hit the URL logged in the console after running the following command on the directory to see your deployed app:
wt create index
I was amazed too!
Now that we have seen a basic example, let's build something serious and interesting -- an API for our Stories app.
API Project Structure
|---middlwares |------db.js |---models |------Story.js |---routes |------stories.js |---package.json |---index.js
The pacakge.json contains the dependencies for this project as well as important scripts to run and bundle our project to be Webtask-ready:
{ "name": "wt-mern-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "npm run create -- --watch", "create": "wt create index --bundle" }, "author": "", "license": "MIT", "dependencies": { "body-parser": "^1.17.1", "express": "^4.15.2", "mongoose": "^4.9.5", "webtask-tools": "^3.2.0" } }
Webtask Programming Model & Express
Webtask integrates best JavaScript. As you have seen, we just exported a function and an app was created. You might be wondering how you could bring in a different programming model to the scene.
Exporting functions is just one of the programming models supported by Webtask. It happens to be the most basic but that not withstanding, you can employ what works for you. In our case we want to use Express.
Webtask has a utility tool, webtask-tools, to help you bind your express app to a Webtask context. Therefore, rather than exporting a simple function, you can export an express app bound to Webtask using webtask-tools:
// ./index.js var Express = require('express'); var Webtask = require('webtask-tools'); var bodyParser = require('body-parser') var app = Express(); app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.json()) // yet to be created app.use(require('./middlewares/db').connectDisconnect); require('./routes/stories')(app); module.exports = Webtask.fromExpress(app);
If you are familiar with Express, you will see a lot of familiar codes. The big change is that rather than listening, we are exporting a function created from the Express app using webtask-tools.
The following lines are yet to be created but the handle database connection/disconnection and routes respectively:
... app.use(require('./middlewares/db').connectDisconnect); require('./routes/stories')(app); ...
Database, Connection, Schema and Model
We are trying as much as possible to be practical enough so you can have a 360 view of how useful Webtask can be. One of such practical situations is using an actual database rather than using a JSON temp file.
Mongolab Database
Mongolab by Object Labs is a good choice for cloud database because they eliminate the challenges of knowing how to setup a Cloud DB by just giving you a URL after choosing where you want your database to be hosted. To get started:
Quickly Sign up.
Create a database. A database URL will be supplied on the dashboard, copy and keep safe.
Create a user to authenticate the database. You can do this by clicking on the just created database, selecting the Users' tab and clicking Add database user.
Mongoose Schema
Mongoose is a library that makes interacting with Mongo DB easier. It provides a more friendly API for connecting, creating, updating and querying your database. To do this, it uses a schemas to map Mongo collections and their properties to JavaScript object.
// ./models/Story.js const mongoose = require('mongoose'); module.exports = new mongoose.Schema({ author: String, content: String, created_at: Date, id: mongoose.Schema.ObjectId })
Connection and Model
Next is to connect to a database and disconnect at the beginning and end of each request. To set this up, we need to use a middleware which will execute before each of our Express routes:
// ./middlewares/db.js var mongoose = require('mongoose'); // import Story schema const StorySchema = require('../models/Story') module.exports = { // Connect/Disconnect middleware connectDisconnect: (req, res, next) => { // Create connection using Mongo Lab URL // available in Webtask context const connection = mongoose.createConnection(req.webtaskContext.secrets.MONGO_URL); // Create a mongoose model using the Schema req.storyModel = connection.model('Story', StorySchema); req.on('end', () => { // Disconnect when request // processing is completed mongoose.connection.close(); }) // Call next to move to // the next Express middleware next() }, }
This middleware handles both connecting and disconnecting to a Mongolab database. The connection is achieved by passing a connection URL to the createConnection method. The URL is received via Webtask context; see next title.
When we establish a connection, we create a Mongoose model and attach the model to our request object.
We then attach an event listener to close the connection at the end of the request. next is called to pass down and continue with whatever middleware is next in the stack. This will most likely be an Express route.
Webtask Context
You can access contextual information via the Webtask context object. Such information can be used to store sensitive credentials like secrets, dynamic details like query strings, etc.
You can access the context via the function parameter:
module.exports = function(context, cb) { cb(null, { hello: context.data.name || 'Anonymous' }); }
When using Express, you can access it from req.webtaskContext just like we saw in the database connection example. The MONGO_URL secret is passed in via the terminal while running the app:
wt create index --secret MONGO_URL=<MONGOLAB-CONNECTION-URL> --bundle
Express CRUD Routes
We have written all the helper codes our routes need to function. Tackling these routes is the next task:
// ./routes/stories.js var mongoose = require('mongoose'); const Story = require('../models/Story'); module.exports = (app) => { app.get('/stories', (req, res) => { req.storyModel.find({}).sort({'created_at': -1}).exec((err, stories) => res.json(stories)) }); app.post('/stories', (req, res) => { const newStory = new req.storyModel(Object.assign({}, req.body, {created_at: Date.now()})); newStory.save((err, savedStory) => { res.json(savedStory) }) }) app.put('/stories', (req, res) => { const idParam = req.webtaskContext.query.id; req.storyModel.findOne({_id: idParam}, (err, storyToUpdate) => { const updatedStory = Object.assign(storyToUpdate, req.body); updatedStory.save((err, story) => res.json(story)) }) }) app.delete('/stories', (req, res) => { const idParam = req.webtaskContext.query.id; req.storyModel.remove({_id: idParam}, (err, removedStory) => res.json(removedStory)); }) }
GET: /stories route uses mongoose to fetch all the stories stored in the database and sort them by date created in descending order
POST: /stories is used to create a new story by storing the payload on req.body
PUT: /stories expects an id query string which it uses to find a story and updates the story based on the id
DELETE: /stories just like PUT, expects an id as well and removes an entry from the database collection based on the id
Final Words
You can hit the following URL using GET in Postman to see a response of an array if stories:
http://ift.tt/2plXqIR
Remember to run the app one more time if you have not been doing so to deploy your functions:
wt create index --secret MONGO_URL=<MONGOLAB-CONNECTION-URL> --bundle
The next part of this article will describe how we will consume these endpoints in a React app so as to have a full application. We will also deploy the React app so has to have everything running on a remote server.
via Scotch.io http://ift.tt/2q836Hm
0 notes